package com.noble.glamour.module.logic.baseui.custom;

import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;

/**
 * 仿{@link android.os.CountDownTimer}实现的正计时Timer
 * 根据需求实现{@link #onDisplay(long)}, {@link #onTick(long)}, {@link #onFinish(long)}三个抽象方法
 * <p>
 * Created by Su on 2017/3/22.
 */

public abstract class CountUpTimer {
    private static final int MSG = 0x11;  // Handler msg

    private final long mCountupInterval;  // 时间递增间隔
    private long mMinllisInStart;         // 初始系统时间
    private long mMillisInFuture;         // 初始开始计时时间
    private long mMillisAtLast;           // 最终统计计时时间
    private boolean mCancelled = false;   // 计时器运行态标记

    public CountUpTimer(long millisInFuture, long countUpInterval) {
        mMillisInFuture = millisInFuture;
        mCountupInterval = countUpInterval;
    }

    /**
     * 关闭计时
     */
    public synchronized final void cancel() {
        mCancelled = true;
        mHandler.removeMessages(MSG);
        onFinish(mMillisAtLast);
    }

    /**
     * 启动计时
     */
    public synchronized final CountUpTimer start() {
        mCancelled = false;
        mMillisAtLast = 0;
        if (mMillisInFuture < 0) {
            mMillisInFuture = 0;
        }
        mMinllisInStart = SystemClock.elapsedRealtime();
        mHandler.sendMessage(mHandler.obtainMessage(MSG));
        return this;
    }

    /**
     * 总共计时时间，用于计时UI展示
     */
    public abstract void onDisplay(long displayMillis);

    /**
     * 实时计时统计
     */
    public abstract void onTick(long millisPass);

    /**
     * 最终计时统计
     */
    public abstract void onFinish(long millisTotal);

    // handler 自增计时
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            synchronized (CountUpTimer.this) {
                if (mCancelled) {
                    return;
                }

                final long millisPass = SystemClock.elapsedRealtime() - mMinllisInStart;
                final long millisDisplay = millisPass + mMillisInFuture;
                mMillisAtLast = millisPass;
                if (millisPass <= 0) {
                    onFinish(millisPass);
                } else if (millisPass < mCountupInterval) {
                    // no tick, just delay until done
                    sendMessageDelayed(obtainMessage(MSG), millisPass);
                } else {
                    long lastTickStart = SystemClock.elapsedRealtime();

                    onDisplay(millisDisplay);
                    onTick(millisPass);

                    // take into account user's onTick taking time to execute
                    long delay = lastTickStart + mCountupInterval - SystemClock.elapsedRealtime();

                    // special case: user's onTick took more than interval to
                    // complete, skip to next interval
                    while (delay < 0) delay += mCountupInterval;

                    sendMessageDelayed(obtainMessage(MSG), delay);
                }
            }
        }
    };
}
